<template>
  <el-dialog
    :visible.sync="dialogVisible"
    title="图片拼接生成器"
    :close-on-click-modal="false"
    @close="handleClose"
    :z-index="100008"
    width="90%"
    max-width="1200px"
  >
    <div class="p-4">
      <div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
        <!-- 左侧：控制面板 -->
        <div class="bg-white rounded-lg shadow-lg p-6">
          <el-form
            :model="formData"
            ref="queryForm"
            size="small"
            label-width="120px"
            class="space-y-4"
          >
            <el-form-item label="选择图片">
              <el-upload
                class="upload-demo"
                drag
                multiple
                action="#"
                :limit="rows * cols"
                :auto-upload="false"
                :on-change="handleFileSelection"
                :on-remove="handleRemove"
                :on-exceed="handleExceed"
                :file-list="selectedImages"
                accept="image/*"
              >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">
                  将图片拖到此处，或
                  <em>点击上传</em>
                </div>
                <div class="el-upload__tip" slot="tip">
                  最多可选择 {{ rows * cols }} 张图片，不足将用背景色填充
                </div>
              </el-upload>
            </el-form-item>

            <el-form-item label="行数">
              <el-input-number
                v-model.number="rows"
                :min="1"
                :max="10"
                @change="updateImageLimit"
              ></el-input-number>
            </el-form-item>

            <el-form-item label="列数">
              <el-input-number
                v-model.number="cols"
                :min="1"
                :max="10"
                @change="updateImageLimit"
              ></el-input-number>
            </el-form-item>

            <el-form-item label="宽高比例">
              <el-radio-group v-model="aspectRatio" @change="previewCollage">
                <el-radio-button label="2.35">2.35:1(电影宽屏)</el-radio-button>
                <el-radio-button label="1.78">1.78:1(16:9)</el-radio-button>
                <el-radio-button label="1.33">1.33:1(4:3)</el-radio-button>
                <el-radio-button label="1">1:1(正方形)</el-radio-button>
              </el-radio-group>
            </el-form-item>

            <el-form-item label="背景颜色">
              <el-color-picker
                v-model="backgroundColor"
                @change="previewCollage"
              ></el-color-picker>
            </el-form-item>
          </el-form>
        </div>

        <!-- 右侧：预览和结果 -->
        <div class="bg-white rounded-lg shadow-lg p-6 flex-col flex-wrap">
          <div class="flex-col">
            <h3 class="text-xl font-semibold mb-4">实时预览</h3>
            <div class="relative overflow-hidden bg-gray-100 rounded-lg mb-4" >
              <canvas ref="previewCanvas" class="absolute inset-0 w-full h-full"></canvas>
            </div>
          </div>

          <div v-if="collageUrl" class="mt-6 flex-col fill-width">
            <h3 class="text-xl font-semibold mb-4">生成结果</h3>
            <div class="relative overflow-hidden bg-gray-100 rounded-lg mb-4" style="width: 60%;">
              <img :src="collageUrl" alt="拼接图片结果" class="absolute inset-0 w-full h-full object-contain fill-width">
            </div>
          </div>
        </div>
      </div>
    </div>

    <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeDialog">取消</el-button>
        <el-button type="primary" @click="generateCollage" :loading="generating" :disabled="selectedImages.length === 0"><i class="el-icon-picture"></i> 生成拼接图</el-button>
        <el-button type="success" @click="uploadCollage" :disabled="!collageUrl"><i class="el-icon-upload"></i> 保存封面</el-button>
        <el-button type="success" @click="downloadCollage" :disabled="!collageUrl"><i class="el-icon-download"></i> 下载图片</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script>
import { updateCoverUrl,upload } from '@/api/imgManage/writeArticles'
export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    articleId: {
      type: String,
      default: () => ''
    }
  },
  data() {
    return {
      dialogVisible: this.visible,
      selectedImages: [],
      rows: 2,
      cols: 3,
      backgroundColor: '#ffffff',
      collageUrl: null,
      blobObj: null,
      generating: false,
      aspectRatio: '2.35',
      formData: {
        rows: 2,
        cols: 3,
        backgroundColor: '#ffffff'
      },
      // 跟踪每个文件的临时URL及其状态
      fileUrlMap: new Map()
    }
  },
  computed: {
    totalCells() {
      return this.rows * this.cols;
    },
    canGenerate() {
      return this.selectedImages.length > 0;
    }
  },
  watch: {
    visible(val) {
      this.dialogVisible = val;
      if (val) {
        this.$nextTick(() => {
          this.previewCollage();
        });
      }
    },
    dialogVisible(val) {
      this.$emit('update:visible', val);
      if (!val) {
        this.cleanupResources();
      }
    },
    rows() {
      this.updateImageLimit();
      this.previewCollage();
    },
    cols() {
      this.updateImageLimit();
      this.previewCollage();
    },
    backgroundColor() {
      this.previewCollage();
    }
  },
  methods: {
    // 生成时间格式的 title（如：2025-07-29 15:30:45）
    generateTitle() {
      const date = new Date();
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, "0");
      const day = String(date.getDate()).padStart(2, "0");
      const hours = String(date.getHours()).padStart(2, "0");
      const minutes = String(date.getMinutes()).padStart(2, "0");
      const seconds = String(date.getSeconds()).padStart(2, "0");
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
    // 调用上传的主方法
    async uploadCollage() {
      if (!this.blobObj) {
        this.$message.error("没有可上传的拼接图片");
        return;
      }
      try {

        // 2. 生成时间格式的 title
        const title = this.generateTitle();

        // 3. 调用上传接口
        const response = await this.uploadImage(this.blobObj, title);

        await updateCoverUrl({ id: this.articleId, coverUrl: response.url})

        // 处理上传成功的逻辑
        this.$message.success("图片上传成功");
        console.log("上传结果:", response);
      } catch (error) {
        // 处理错误
        this.$message.error(`上传失败: ${error.message}`);
        console.error("转换或上传出错:", error);
      }
    },
    // 上传图像到服务器
    async uploadImage(blob, title) {
      try {
        // 创建FormData对象
        const formData = new FormData();
        formData.append('file', blob, `${title}.png`);
        // 发送请求到后端
        const response = await upload(formData);
        console.log('uploadResponse ', response)
        return response;
      } catch (error) {
        console.error('上传过程中出错:', error);
        throw error;
      }
    },

    // 处理文件选择
    handleFileSelection(file, fileList) {
      if (!file) return false;

      this.selectedImages = fileList;
      this.previewCollage();
      return false;
    },

    // 处理图片移除
    handleRemove(file, fileList) {
      // 移除文件时清理对应的临时URL
      if (file.raw && this.fileUrlMap.has(file.uid)) {
        URL.revokeObjectURL(this.fileUrlMap.get(file.uid));
        this.fileUrlMap.delete(file.uid);
      }

      this.selectedImages = fileList;
      this.previewCollage();
    },

    // 处理超出限制
    handleExceed(files, fileList) {
      this.$message.warning(`最多只能选择${this.totalCells}张图片`);
    },

    // 更新图片数量限制
    updateImageLimit() {
      if (this.selectedImages.length > this.totalCells) {
        // 移除多余图片时清理对应的临时URL
        const removedFiles = this.selectedImages.slice(this.totalCells);
        removedFiles.forEach(file => {
          if (file.raw && this.fileUrlMap.has(file.uid)) {
            URL.revokeObjectURL(this.fileUrlMap.get(file.uid));
            this.fileUrlMap.delete(file.uid);
          }
        });

        this.selectedImages = this.selectedImages.slice(0, this.totalCells);
        this.$message.warning(`已自动保留前${this.totalCells}张图片，最多只能选择这么多`);
      }
      this.previewCollage();
    },

    // 预览拼接效果
    previewCollage() {
      const canvas = this.$refs.previewCanvas;
      if (!canvas) return;

      const ctx = canvas.getContext('2d');

      // 设置canvas尺寸（基于行列比）
      const targetWidth = 800;
      canvas.width = targetWidth;
      canvas.height = targetWidth * (this.rows / this.cols);

      this.drawCollage(ctx, canvas.width, canvas.height);
    },

    // 生成最终拼接图
    async generateCollage() {
      if (this.selectedImages.length === 0) {
        this.$message.warning('请先选择图片');
        return;
      }

      this.generating = true;

      try {
        // 第一步：创建原始拼接图（按行列比例）
        const originalCanvas = document.createElement('canvas');
        const originalWidth = 3840;
        originalCanvas.width = originalWidth;
        originalCanvas.height = originalWidth * (this.rows / this.cols);
        const originalCtx = originalCanvas.getContext('2d');

        // 绘制原始拼接内容
        await this.drawCollage(originalCtx, originalCanvas.width, originalCanvas.height, true);

        // 第二步：根据选择的比例创建最终图片并添加填充
        const targetRatio = parseFloat(this.aspectRatio);
        const originalRatio = originalCanvas.width / originalCanvas.height;

        let finalWidth, finalHeight;
        let offsetX = 0, offsetY = 0;

        // 计算最终尺寸和偏移量（确保比例正确并居中放置原始内容）
        if (targetRatio > originalRatio) {
          // 目标更宽，上下填充
          finalHeight = originalCanvas.height;
          finalWidth = finalHeight * targetRatio;
          offsetX = (finalWidth - originalCanvas.width) / 2;
        } else {
          // 目标更高，左右填充
          finalWidth = originalCanvas.width;
          finalHeight = finalWidth / targetRatio;
          offsetY = (finalHeight - originalCanvas.height) / 2;
        }

        // 创建最终画布
        const finalCanvas = document.createElement('canvas');
        finalCanvas.width = finalWidth;
        finalCanvas.height = finalHeight;
        const finalCtx = finalCanvas.getContext('2d');

        // 填充背景色
        finalCtx.fillStyle = this.backgroundColor;
        finalCtx.fillRect(0, 0, finalWidth, finalHeight);

        // 绘制原始拼接图（居中放置）
        finalCtx.drawImage(originalCanvas, offsetX, offsetY);

        // 生成图片URL
        finalCanvas.toBlob(blob => {
          // 清理之前的blob对象
          if (typeof this.collageUrl === 'string' && this.collageUrl.startsWith('blob:')) {
            URL.revokeObjectURL(this.collageUrl);
            this.blobObj = null
          }

          this.collageUrl = URL.createObjectURL(blob);
          this.blobObj = blob
          this.generating = false;
          this.$message.success('图片生成成功！');
          this.$emit('on-success', this.collageUrl);
        }, 'image/jpeg', 0.95);
      } catch (error) {
        console.error('生成图片失败:', error);
        this.generating = false;
        this.$message.error('生成图片失败，请重试');
      }
    },

    // 绘制拼接图
    drawCollage(ctx, width, height, isFinal = false) {
      return new Promise((resolve) => {
        // 清除画布（背景色统一）
        ctx.fillStyle = this.backgroundColor;
        ctx.fillRect(0, 0, width, height);

        const totalImages = Math.min(this.selectedImages.length, this.totalCells);
        let loadedImages = 0;

        // 计算每个格子的尺寸（无额外间距）
        const cellWidth = width / this.cols;
        const cellHeight = height / this.rows;

        if (totalImages === 0) {
          resolve();
          return;
        }

        // 绘制每个图片
        for (let row = 0; row < this.rows; row++) {
          for (let col = 0; col < this.cols; col++) {
            const index = row * this.cols + col;
            if (index >= totalImages) break;

            const file = this.selectedImages[index];
            let imgUrl = file.url;

            if (file.raw) {
              if (!this.fileUrlMap.has(file.uid)) {
                const tempUrl = URL.createObjectURL(file.raw);
                this.fileUrlMap.set(file.uid, tempUrl);
                imgUrl = tempUrl;
              } else {
                imgUrl = this.fileUrlMap.get(file.uid);
              }
            }

            const img = new Image();
            img.crossOrigin = "anonymous";
            img.src = imgUrl;

            img.onload = () => {
              // 保持图片原始宽高比（不变形）
              const imgAspect = img.width / img.height;

              // 计算缩放比例：确保图片完整放入格子
              const scaleByWidth = cellWidth / img.width;
              const heightByWidth = img.height * scaleByWidth;

              const scaleByHeight = cellHeight / img.height;
              const widthByHeight = img.width * scaleByHeight;

              // 选择最大安全缩放比例（不变形）
              let scaleRatio;
              if (heightByWidth <= cellHeight) {
                scaleRatio = scaleByWidth; // 按宽度缩放
              } else {
                scaleRatio = scaleByHeight; // 按高度缩放
              }

              // 缩放后尺寸（严格按比例）
              const drawWidth = img.width * scaleRatio;
              const drawHeight = img.height * scaleRatio;

              // 左/上对齐，紧密排列
              const drawX = col * cellWidth;
              const drawY = row * cellHeight;

              // 绘制图片
              ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);

              loadedImages++;
              if (loadedImages === totalImages) {
                if (isFinal) {
                  this.cleanupTempUrls();
                }
                resolve();
              }
            };

            img.onerror = () => {
              console.error('图片加载失败:', file.name);
              ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
              ctx.fillRect(col * cellWidth, row * cellHeight, cellWidth, cellHeight);
              ctx.fillStyle = 'red';
              ctx.font = '14px Arial';
              ctx.textAlign = 'center';
              ctx.textBaseline = 'middle';
              ctx.fillText('加载失败', col * cellWidth + cellWidth/2, row * cellHeight + cellHeight/2);
              loadedImages++;
              if (loadedImages === totalImages) {
                resolve();
              }
            };
          }
        }
      });
    },

    // 下载图片
    downloadCollage() {
      if (!this.collageUrl) return;

      const link = document.createElement('a');
      link.href = this.collageUrl;
      link.download = `collage_${this.rows}x${this.cols}_${this.aspectRatio.replace('.', 'x')}.jpg`;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      this.$emit('on-download');
    },

    // 关闭对话框
    closeDialog() {
      this.dialogVisible = false;
      this.$emit('on-close');
    },

    // 处理对话框关闭
    handleClose() {
      this.$emit('on-close');
    },

    // 清理临时URL
    cleanupTempUrls() {
      this.fileUrlMap.forEach(url => {
        URL.revokeObjectURL(url);
      });
      this.fileUrlMap.clear();
    },

    // 清理资源
    cleanupResources() {
      this.cleanupTempUrls();
      if (typeof this.collageUrl === 'string' && this.collageUrl.startsWith('blob:')) {
        URL.revokeObjectURL(this.collageUrl);
        this.collageUrl = null;
      }
      this.selectedImages = [];
      this.generating = false;
    }
  },
  mounted() {
    if (this.dialogVisible) {
      this.previewCollage();
    }
  },
  beforeDestroy() {
    this.cleanupResources();
  }
}
</script>

<style scoped>
canvas {
  display: block;
}

.upload-demo {
  margin-bottom: 16px;
}

.el-upload__tip {
  margin-top: 8px;
}

@media (max-width: 768px) {
  .grid-cols-3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

.relative.group:hover img {
  filter: brightness(0.9);
  transition: filter 0.3s ease;
}

.el-button--mini {
  padding: 4px;
  width: 24px;
  height: 24px;
}

.generating-indicator {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}

.el-radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
</style>
